package com.hhkj.admin.student.service.biz.impl;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.hhkj.admin.bank.domain.Bank;
import com.hhkj.admin.bank.service.base.BankService;
import com.hhkj.admin.course.domain.Course;
import com.hhkj.admin.course.model.req.CourseReq;
import com.hhkj.admin.course.service.base.CourseService;
import com.hhkj.admin.student.common.cont.StudentBatchConst;
import com.hhkj.admin.student.common.extend.BatchStudentModel;
import com.hhkj.admin.student.domain.StudentBatch;
import com.hhkj.admin.student.domain.StudentCourse;
import com.hhkj.admin.student.model.dopo.StudentBatchDo;
import com.hhkj.admin.student.model.dopo.StudentBatchPo;
import com.hhkj.admin.student.model.dopo.StudentPo;
import com.hhkj.admin.student.model.req.StudentBatchReq;
import com.hhkj.admin.student.model.req.StudentCourseReq;
import com.hhkj.admin.student.model.req.StudentReq;
import com.hhkj.admin.student.model.res.StudentBatchRes;
import com.hhkj.admin.student.service.base.StudentBatchService;
import com.hhkj.admin.student.service.base.StudentCourseService;
import com.hhkj.admin.student.service.biz.StudentBatchBizService;
import com.hhkj.admin.student.service.extend.StudentBatchExtendService;
import com.ruoyi.common.base.biz.service.biz.BaseBizServiceImpl;
import com.hhkj.admin.student.common.cont.StudentConst;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.exception.GlobalException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.excl.workbook.CellUtils;
import com.ruoyi.common.utils.excl.workbook.FontUtils;
import com.ruoyi.common.utils.excl.workbook.RowUtils;
import com.ruoyi.common.utils.excl.workbook.SheetUtils;
import org.apache.poi.ss.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 学员批次BizService接口
 *
 * @author ruoyi
 * @since 2023-06-08
 */
@Service
public class StudentBatchBizServiceImpl
        extends BaseBizServiceImpl<StudentBatch, StudentBatchReq, StudentBatchRes, StudentBatchDo, StudentBatchPo,
        StudentBatchService, StudentBatchExtendService>
        implements StudentBatchBizService
{
    @Autowired
    private BankService bankService;
    @Autowired
    private CourseService courseService;
    @Autowired
    private StudentBatchService studentBatchService;
    @Autowired
    private StudentCourseService studentCourseService;

    /**
     * 查询学员批次管理列表
     *
     * @param studentBatchReq 学员批次管理
     * @return 学员批次管理
     */
    @Override
    public List<StudentBatchPo> selectStudentBatchList(StudentBatchReq studentBatchReq)
    {
        //补充参数
        applyCondition(studentBatchReq);
        //查询数据库
        List<StudentBatchPo> studentBatches = studentBatchService.selectStudentBatchListByDo(studentBatchReq);
        //关联
        List<Long> batchIds = studentBatches.stream().map(StudentBatchPo::getId).collect(Collectors.toList());
        if (batchIds.size() == 0) {
            return studentBatches;
        }
        List<StudentCourse> studentCourseList = studentCourseService.list(Wrappers.<StudentCourse>lambdaQuery()
                .in(StudentCourse::getBatchId, batchIds));
        for (StudentBatchPo batch : studentBatches) {
            //关联学员课程信息
            List<StudentCourse> studentCourses = studentCourseList
                    .stream()
                    .filter(o -> o.getBatchId().equals(batch.getId())).collect(Collectors.toList());
//            batch.setStudentCourseList(studentCourses);
            //学员数量
            batch.setStudentNum(studentCourses.size());
            //学员总缴费金额
            batch.setStudentTotalPrice(studentCourses.stream().map(StudentCourse::getUnitPayPrice).reduce(BigDecimal.ZERO,BigDecimal::add));
        }
        return studentBatches;
    }

    /**
     * 根据登陆人进行数据过滤
     *
     * @param studentBatchReq 入参
     */
    private void applyCondition(StudentBatchReq studentBatchReq)
    {
        if (!SysUser.isAdminTypeCode(SecurityUtils.getTypeCode())) {
            studentBatchReq.setInsId(SecurityUtils.getUserId());
        }
    }

    /**
     * 批量删除学员批次管理
     *
     * @param idList 需要删除的学员批次管理主键
     * @return 结果
     */
    @Override
    public boolean removeStudentBatchByIdList(List<Long> idList)
    {
        //判断是否批次下有已审核通过的学员
        long count = studentCourseService.count(Wrappers.<StudentCourse>lambdaQuery()
                .in(StudentCourse::getBatchId, idList)
                .eq(StudentCourse::getStatus, StudentConst.AuditCode.STATUS_PASS.getCode()));
        if (count > 0) {
            throw new GlobalException("批次下有已审核通过的学员，无法删除！");
        }
        //删除关联的学员课程
        studentCourseService.getBaseMapper().delete(Wrappers.<StudentCourse>lambdaQuery()
                .in(StudentCourse::getBatchId, idList));
        return studentBatchService.removeBatchByIds(idList);
    }

    /**
     * 学员批次缴费
     *
     * @param studentBatchReq 入参
     */
    @Override
    public boolean payBatch(StudentBatchReq studentBatchReq)
    {
        verifyParam(studentBatchReq);
        studentBatchReq.setPayFlag(1L);
        return studentBatchService.updateById(studentBatchReq);
    }

    /**
     * 查询批次下学员列表
     *
     * @param studentBatch 批次号id
     * @return 学员
     */
    @Override
    public boolean updatePay(StudentBatchReq studentBatch) {
        verifyParam(studentBatch);
        return studentBatchService.updateById(studentBatch);
    }

    /**
     * 校验参数
     *
     * @param studentBatch 传参
     */
    private void verifyParam(StudentBatchReq studentBatch)
    {
        if (ObjectUtil.isEmpty(studentBatch.getId())) {
            throw new GlobalException("批次主键不能为空！");
        }
        if (ObjectUtil.isEmpty(studentBatch.getPayPrice())) {
            throw new GlobalException("缴费金额未传！");
        }
        if (ObjectUtil.isEmpty(studentBatch.getPayDate())) {
            throw new GlobalException("缴费日期未传！");
        }
    }

    /**
     * 查询批次下学员列表
     *
     * @param studentBatchReq 批次号id
     * @return 学员
     */
    @Override
    public List<StudentPo> listBatchStudent(StudentBatchReq studentBatchReq)
    {
        return studentCourseService.listBatchStudentPoByDo(studentBatchReq);
    }

    /**
     * 校验给定的科目是否属于同一个类别
     *
     * @param course 科目id list
     * @return boolean true属于同一类别
     */
    @Override
    public boolean verifyCourseCategory(CourseReq course)
    {
        List<Course> courseList = courseService.getBaseMapper().selectList(Wrappers.<Course>lambdaQuery()
                .in(Course::getId, course.getIdList()));
        List<Long> parentIdList = courseList.stream()
                .map(Course::getParentId)
                .distinct()
                .collect(Collectors.toList());
        if (parentIdList.size() > 1) {
            throw new GlobalException("当前选择的学员属于不同课程类别，无法批量设置题库类型，请重新选择");
        } else {
            return true;
        }
    }


    /**
     * 批量审核学员
     *
     * @param studentReq 传参
     */
    @Override
    public void checkBatchStudent(StudentReq studentReq) {
        //2023年5月24日 判断学员科目是否已经有上架的题库，没有就不允许审核
        checkCourseBank(studentReq);
        //2023年6月27日 判断同科目是否已经有处于审核状态的学员，有就不允许审核
        checkSameCourseStudentStatus(studentReq);
        //修改学员的状态
        studentCourseService.updateBatchStatusByIdList(studentReq.getIdList(), studentReq.getStatus());
        //如果改为未审核，则清空到期日期和题库类型
        cleanInfo(studentReq);
        //更改批次的状态 1未审核 2已通过
        editBatchStatus(studentReq);
    }

    /**
     * 判断同科目是否已经有处于审核状态的学员，有就不允许审核
     *
     * @param studentReq 学员科目
     */
    private void checkSameCourseStudentStatus(StudentReq studentReq) {
        if (StudentConst.AuditCode.STATUS_PASS.getCode().equals(studentReq.getStatus())) {
            //查询本次审批的全部数据，以主键为键生成map
            List<StudentCourse> studentCourseList = studentCourseService.list(Wrappers.<StudentCourse>lambdaQuery()
                    .in(StudentCourse::getId, studentReq.getIdList()));
            //以主键为键生成map
            Map<Long, List<StudentCourse>> idStudentCourseList = studentCourseList
                    .stream()
                    .collect(Collectors.groupingBy(StudentCourse::getId));
            //查询本次处理的全部学员的全部科目信息
            List<StudentCourse> passStudentCourse = getPassStudentCourse(studentCourseList);
            if (passStudentCourse != null && passStudentCourse.size() > 0) {
                //遍历
                for (Long conCourseId : studentReq.getIdList()) {
                    if (idStudentCourseList.containsKey(conCourseId)) {
                        StudentCourse studentCourse = idStudentCourseList.get(conCourseId).get(0);
                        //检查该学员是否有同科目已审核通过状态的数据
                        boolean b = passStudentCourse.stream()
                                .anyMatch(o -> o.getStudentId().equals(studentCourse.getStudentId())
                                        && o.getCourseId().equals(studentCourse.getCourseId()));
                        if (b) {
                            throw new GlobalException("有学员同科目下已经存在审核通过状态的数据！");
                        }
                    }
                }
            }
        }
    }

    /**
     * 查询本次处理的全部学员的已审核通过状态的studentCourse数据
     *
     * @param studentCourseList 已审核通过状态的studentCourse数据
     */
    private List<StudentCourse> getPassStudentCourse(List<StudentCourse> studentCourseList) {
        List<Long> studentList = studentCourseList.stream().map(StudentCourse::getStudentId).collect(Collectors.toList());
        return studentCourseService.list(Wrappers.<StudentCourse>lambdaQuery()
                .in(StudentCourse::getStudentId, studentList)
                .eq(StudentCourse::getStatus, StudentConst.AuditCode.STATUS_PASS.getCode()));
    }

    /**
     * 判断学员科目是否已经有上架的题库，没有就不允许审核通过
     *
     * @param studentReq 学员科目
     */
    private void checkCourseBank(StudentReq studentReq) {
        if (StudentConst.AuditCode.STATUS_PASS.getCode().equals(studentReq.getStatus())) {
            List<StudentCourse> studentCourses = studentCourseService.getBaseMapper().selectList(Wrappers.<StudentCourse>lambdaQuery()
                    .in(StudentCourse::getId, studentReq.getIdList()));
//            boolean lineDateFlag = studentCourses.stream().anyMatch(o -> o.getLineDate() == null);
//            if (lineDateFlag) {
//                throw new GlobalException("未指定到期日期，禁止审核！");
//            }
            List<Long> courseIds = studentCourses.stream().map(StudentCourse::getCourseId).collect(Collectors.toList());
            //查询选择学员的科目
            List<Course> courses = courseService.getBaseMapper().selectList(Wrappers.<Course>lambdaQuery().in(Course::getId, courseIds));
            //查询这些科目的上架题库
            List<Long> courseIdList = courses.stream().map(Course::getId).collect(Collectors.toList());
            List<Bank> banks = bankService.list(Wrappers.<Bank>lambdaQuery()
                    .in(Bank::getCourseId, courseIdList)
                    .eq(Bank::getPublishFlag, 1));
            if (banks == null || banks.size() == 0) {
                throw new GlobalException("选择的学员科目全部无上架的题库，不允许审核！");
            }
            List<Long> publishBankCourseIdList = banks.stream().map(Bank::getCourseId).collect(Collectors.toList());
            List<String> errorCourseName = Lists.newArrayList();
            for (Course course : courses) {
                boolean b = publishBankCourseIdList.stream().anyMatch(o -> o.equals(course.getId()));
                if (!b) {
                    errorCourseName.add(course.getName());
                }
            }
            if (errorCourseName.size() > 0) {
                throw new GlobalException("存在没有上架题库的科目：" + errorCourseName);
            }
        }
    }

    /**
     * 如果状态修改为未审核，则清空到期日期和题库类型
     *
     * @param studentReq 传参
     */
    private void cleanInfo(StudentReq studentReq)
    {
        if (StudentConst.AuditCode.STATUS_NO_CHECK.getCode().equals(studentReq.getStatus())) {
            studentCourseService.cleanInfoByIdList(studentReq.getIdList());
        }
    }

    /**
     * 更改批次的状态 1未审核 2已通过
     * 2023年6月14日 逻辑改为 ：批次中存在待审核状态的学员，批次=待审核；批次全部审核完成=已审核
     * @param studentReq 传参
     */
    private void editBatchStatus(StudentReq studentReq)
    {
        if (StudentConst.AuditCode.STATUS_PASS.getCode().equals(studentReq.getStatus())) {
            //2023年6月14日 审核通过的话，检查该批次下有未审核的学员没有，没有就改为已审核
            Long aLong = studentCourseService.getBaseMapper().selectCount(Wrappers.<StudentCourse>lambdaQuery()
                    .eq(StudentCourse::getBatchId, studentReq.getBatchId())
                    .eq(StudentCourse::getStatus, StudentConst.AuditCode.STATUS_NO_CHECK.getCode()));
            if (aLong == 0) {
                LambdaUpdateWrapper<StudentBatch> update = new LambdaUpdateWrapper<StudentBatch>();
                update.set(StudentBatch::getStatus, StudentBatchConst.AuditCode.HAVE_CHECK.getCode())
                        .eq(StudentBatch::getId, studentReq.getBatchId());
                studentBatchService.update(update);
            }
        } else {
            //2023年6月14日 恢复未审核的话，该批次直接就是未审核
            LambdaUpdateWrapper<StudentBatch> update = new LambdaUpdateWrapper<StudentBatch>();
            update.set(StudentBatch::getStatus, StudentBatchConst.AuditCode.NO_CHECK.getCode())
                    .eq(StudentBatch::getId, studentReq.getBatchId());
            studentBatchService.update(update);
        }
    }


    /**
     * 批量设置题库类型
     *
     * @param studentCourseReq 传参
     */
    @Override
    public void supplyBatchBankType(StudentCourseReq studentCourseReq) {
        if (studentCourseReq.getCourseBankTypeId() == null || studentCourseReq.getIdList() == null) {
            throw new GlobalException("参数传递错误！");
        }
        studentCourseService.updateStudentCourseByIdList(studentCourseReq.getIdList(), studentCourseReq);
    }

    /**
     * 批量设置到期日期
     *
     * @param studentCourseReq 传参
     */
    @Override
    public void supplyBatchLineDate(StudentCourseReq studentCourseReq) {
        if (studentCourseReq.getLineDate() == null || studentCourseReq.getIdList() == null) {
            throw new GlobalException("参数传递错误！");
        }
        List<Long> idList = studentCourseReq.getIdList();
        long count = studentCourseService.count(Wrappers.<StudentCourse>lambdaQuery()
                .in(StudentCourse::getId, idList)
                .eq(StudentCourse::getStatus, StudentConst.AuditCode.STATUS_NO_CHECK.getCode()));
        if (count > 0) {
            throw new GlobalException("未审核通过学员禁止设置到期日期!");
        }
        //修改到期日期到今天以后,修改到期日期的同时，状态再次改为已审核
        if (studentCourseReq.getLineDate().after(DateUtil.beginOfDay(new Date()))) {
            studentCourseReq.setStatus(StudentConst.AuditCode.STATUS_PASS.getCode());
        }
        studentCourseService.updateStudentCourseByIdList(studentCourseReq.getIdList(), studentCourseReq);
    }

    /**
     * 批量设置学员单价
     *
     * @param studentCourseReq 传参
     */
    @Override
    public void supplyBatchStudentUnitPrice(StudentCourseReq studentCourseReq) {
        if (studentCourseReq.getUnitPayPrice() == null || studentCourseReq.getIdList() == null) {
            throw new GlobalException("参数传递错误！");
        }
        studentCourseService.updateStudentCourseByIdList(studentCourseReq.getIdList(), studentCourseReq);
    }

    /**
     * 导出批次下学员的数据
     *
     * @param studentBatchReq 传参
     * @return
     */
    @Override
    public StudentBatch exportStudent(StudentBatchReq studentBatchReq) {
        //处理查询出来的数据
        StudentBatchPo studentBatchPo = queryAndDealDataFromDb(studentBatchReq);
        //编辑表格样式
        return applyExclFont(studentBatchPo);
    }

    /**
     * 统计批次下全部学员的缴费总金额
     *
     * @param batchId 批次id
     * @return 缴费总金额
     */
    @Override
    public StudentBatchRes countBatchStudentPrice(Long batchId) {
        StudentBatchRes res = new StudentBatchRes();
        //批次缴费
        StudentBatch studentBatch = studentBatchService.getById(batchId);
        res.setPayPrice(studentBatch.getPayPrice());
        //学员缴费总额
        BigDecimal studentTotalPrice = studentCourseService.countBatchStudentPrice(batchId);
        res.setStudentTotalPrice(studentTotalPrice);
        return res;
    }

    /**
     * 数据库查询批次、学员数据并处理
     *
     * @param studentBatchReq 传参
     * @return
     */
    private StudentBatchPo queryAndDealDataFromDb(StudentBatchReq studentBatchReq) {
        List<StudentBatchPo> studentBatches = studentBatchService.selectStudentBatchListByDo(studentBatchReq);
        StudentBatchPo studentBatch=new StudentBatchPo();
        if (studentBatches.size() > 0) {
            studentBatch = studentBatches.get(0);
        }

        List<StudentPo> students = studentCourseService.listBatchStudentPoByDo(studentBatchReq);
        if (students.size() == 0) {
            throw new GlobalException("该批次下没有学员");
        }
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        List<BatchStudentModel> collect = students.stream()
                .map(o -> {
                    BatchStudentModel batchStudentModel = new BatchStudentModel();
                    BeanUtil.copyProperties(o, batchStudentModel);
                    accountTimeLimit(df, o, batchStudentModel);
                    return batchStudentModel;
                }).collect(Collectors.toList());
        studentBatch.setStudentModelList(collect);
        return studentBatch;
    }

    /**
     * 处理学员账号期限
     *
     * @param df                时间格式化
     * @param o                 学员
     * @param batchStudentModel 导出类
     */
    private void accountTimeLimit(SimpleDateFormat df, StudentPo o, BatchStudentModel batchStudentModel) {
        String startDate = o.getStartDate() != null ? df.format(o.getStartDate()) : "未指定";
        String lineDate = o.getLineDate() != null ? df.format(o.getLineDate()) : "未指定";
        batchStudentModel.setAccountTimeLimit(startDate + "~" + lineDate);
    }

    /**
     * 给表格添加样式
     *
     * @param studentBatchPo 批次数据
     * @return 数据表格
     */
    private StudentBatch applyExclFont(StudentBatchPo studentBatchPo) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String payFlag = studentBatchPo.getPayFlag() == 1 ? "已缴费" : "未缴费";
        String payDate = studentBatchPo.getPayDate() == null ? "暂无" : dateFormat.format(studentBatchPo.getPayDate());
        String payPrice = studentBatchPo.getPayPrice() == null ? "暂无" : studentBatchPo.getPayPrice().toString();
        String nickName = studentBatchPo.getNickName();
        List<BatchStudentModel> studentModelList = studentBatchPo.getStudentModelList();
        BigDecimal studentTotalPrice = BigDecimal.ZERO;
        if (studentModelList != null && studentModelList.size() > 0) {
            studentTotalPrice = studentModelList.stream()
                    .map(BatchStudentModel::getUnitPayPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
        }
        //设置标题
        String excelTitle = "批次学员数据\n" +
                "1、缴费情况：" + payFlag + "\n" +
                "2、缴费日期：" + payDate + "\n" +
                "3、缴费金额：" + payPrice + "\n" +
                "4、学员总价：" + studentTotalPrice + "\n" +
                "5、所属机构：" + nickName + "\n" +
                " ";
        Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(excelTitle, BatchStudentModel.SHEET_NAME), BatchStudentModel.class, studentBatchPo.getStudentModelList());
        Sheet firstSheet = SheetUtils.getFirstSheet(workbook);
        Row firstRow = RowUtils.getFirstRow(firstSheet);
        Cell titleCell = CellUtils.getFirstCell(firstRow);
        // 设置标题行高
        CellUtils.wrapText(workbook, titleCell);
        RowUtils.setHeight(firstRow, BatchStudentModel.TITLE_HEIGHT);
        //标题字体格式
        Font titleFont = FontUtils.createFont(workbook, BatchStudentModel.EXCEL_NAME_FONT_HEIGHT, true, Font.COLOR_RED);
        CellUtils.updatePartContentFont(titleCell, titleFont, BatchStudentModel.EXCEL_NAME);
        //填充字体格式
        Font font = FontUtils.createFont(workbook, BatchStudentModel.FILL_DATA_FONT_HEIGHT, true, Font.COLOR_NORMAL);
        CellUtils.updatePartContentFont(titleCell, font, payFlag);
        CellUtils.updatePartContentFont(titleCell, font, payDate);
        CellUtils.updatePartContentFont(titleCell, font, nickName);
        CellUtils.updatePartContentFont(titleCell, font, studentTotalPrice.toString());
        CellUtils.updatePartContentFont(titleCell, font, payPrice);
        //列宽自适应
        SheetUtils.autoSizeColumn(workbook, 0, 1, 5);
        studentBatchPo.setWorkbook(workbook);
        return studentBatchPo;
    }

    /**
     * 解绑微信
     *
     * @param studentBatchReq 传参
     */
    @Override
    public int cancelBind(StudentBatchReq studentBatchReq) {
       return studentCourseService.cancelBind(studentBatchReq);
    }
}
